#pragma once
/*
双缓冲区设计
*/
#include"buffer.hpp"
#include<functional>
#include<mutex>
#include<atomic>
#include<condition_variable>
#include<thread>
namespace zxlog{
    class AsyncLooper{
        public:
            enum class AsyncType{
                ASYNC_SAFE = 0,
                ASYNC_UNSAFE
            };
            using Functor = std::function<void(Buffer& buf)>;
            using ptr = std::shared_ptr<AsyncLooper>;
            AsyncLooper(const Functor& cb,AsyncType looper_type)
            :_callback(cb),
            _looper_type(looper_type),
            _thread(std::thread(&AsyncLooper::ThreadEntry,this)),//ThreadEntry必须指定作用域
            _stop(false)
            {}
            ~AsyncLooper(){
                stop();
            }
            void stop()
            {
                _stop = true;   
                _con_cond.notify_all();
                _thread.join();
            }
            void push(const char*data,size_t len)
            {
                //1.加锁，防止多个线程同时向缓冲区写入数据
                std::unique_lock<std::mutex> lock(_mutex);
                //2.如果是安全模式，需要判断可写大小需要大于等于数据长度
                if(_looper_type == AsyncType::ASYNC_SAFE){
                    _pro_cond.wait(lock,[&](){
                            return _pro_buffer.writerAbleSize() >= len;
                            });
                }
                //3.向输入缓冲区中写入数据
                _pro_buffer.push(data,len);
                //4.唤醒消费者
                _con_cond.notify_one();
            }
        private:
            void ThreadEntry(){
                while(!_stop)
                {
                    //对锁设置作用域
                    {
                       //1.加锁，防止消费者和生产者产生锁冲突
                       std::unique_lock<std::mutex> lock(_mutex);
                       //if(_stop == true && _pro_buffer.empty())return;
                       //2.判断写入缓冲区是否有数据，有数据则进行输出
                       _con_cond.wait(lock,[&](){
                               return _stop||!_pro_buffer.empty();
                               });
                       if(!_pro_buffer.empty())
                       {
                           _con_buffer.swap(_pro_buffer);
                       }
                       if(_looper_type == AsyncType::ASYNC_SAFE)
                           _pro_cond.notify_all();
                    }
                    //3.输出数据
                    _callback(_con_buffer);
                    //4.重置缓冲区
                    _con_buffer.reset();
                }
            }
        private:
            Functor _callback;
        private:
            AsyncType _looper_type;
            std::mutex _mutex;
            std::atomic<bool> _stop;
            Buffer _pro_buffer;
            Buffer _con_buffer;
            std::thread _thread;//工作线程
            std::condition_variable _pro_cond;
            std::condition_variable _con_cond;
    };
}
